#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define MAXNITEMS		100000
#define MAXNTHREADS		100
#define min(a,b)		(a)<(b)?(a):(b)

int nitems;
struct {
	pthread_mutex_t mutex;
	int buff[MAXNITEMS];
	int nput;
	int nval;
} shared = {
	PTHREAD_MUTEX_INITIALIZER	
};

void * produce(void *),*consume(void *);

int main(int argc,char ** argv)
{
	int i,nthreads,count[MAXNITEMS];
	pthread_t tid_product[MAXNTHREADS],tid_consume;
	
	if(argc!=3)
	{
		printf("use arg nothing");
		exit(1);
	}

	nitems = min(atoi(argv[1]),MAXNITEMS);
	nthreads = min(atoi(argv[2]),MAXNTHREADS);
	printf("nitems = %d\n",nitems);
	printf("nthreads = %d\n",nthreads);


	int curlev = pthread_getconcurrency();
	printf("cur level = %d\n",curlev);

	//pthread_setconcurrency(nthreads);

	int _errno=0;
	for(i=0;i<nthreads;i++)
	{
		count[i] = 0;
		if((_errno=pthread_create(&tid_product[i],NULL,produce,&count[i]))!=0)
		{
			printf("pthread_create %d error:%d %s\n",i,_errno,strerror(_errno));
			exit(1);
		}

	}

	for(i=0;i<nthreads;i++)
	{
		if((_errno=pthread_join(tid_product[i],NULL))!=0)
		{
			printf("pthread_join:");
			exit(1);
		}
		printf("count[%d]=%d\n",i,count[i]);
	}

	if((_errno=pthread_create(&tid_consume,NULL,consume,NULL))!=0)
	{
		printf("pthread_create consume");
		exit(1);
	}

	if((_errno = pthread_join(tid_consume,NULL))!=0)
	{
		printf("pthread_join tid_consume");
		exit(1);
	}


	exit(0);
}

void * produce(void * arg)
{
	int _errno=0;
	for(;;)
	{
		if((_errno=pthread_mutex_lock(&shared.mutex))!=0)
		{
			printf("pthread_mutex_lock:");
			pthread_exit(0);
		}
		if(shared.nput >= nitems)
		{
			pthread_mutex_unlock(&shared.mutex);
			return (NULL);
		}
		shared.buff[shared.nput] = shared.nval;
//		printf("shared.nput = %d\n",shared.nput);
//		printf("shared.buff = %d\n",shared.buff[shared.nput]);
		shared.nput++;
		shared.nval++;
		pthread_mutex_unlock(&shared.mutex);
		*((int *)arg)+=1;
	}
}


void * consume(void * arg)
{
	int i;
	for(i=0;i<nitems;i++)
	{
		if(shared.buff[i] !=i)
			printf("buff[%d] = %d\n",i,shared.buff[i]);
	}
	return (NULL);
}

